package com.sensePlusVR.utils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class DownloadBatchUrl {

	private static String TAG = "DownloadBatchUrl";
	private static BlockingQueue<DownloadTask> tasks = new LinkedBlockingQueue<DownloadTask>();
	private Map<String, cacheSize> sizeMap = new HashMap<String, cacheSize>();
	// private static List<downloadTask> done = new ArrayList<downloadTask>();
	private static DownloadBatchUrl INSTANTS;
	private static boolean stoped = false;
	private DownloadTask inWorking;

	private UpdataThread thread;

	public static DownloadBatchUrl getInstants() {
		
		if(INSTANTS==null){
			
			INSTANTS = new DownloadBatchUrl();
			
		}	
		return INSTANTS;
	}
	

	private int calcProgress(long done, long totel){
		if (totel == 0)
			return 0;
		return (int) (done * 100 / totel);
	}
	
	private class cacheSize{
		public int totolSize;
		public int doneSize;
		public cacheSize(int totol, int done){
			totolSize = totol;
			doneSize = done;
		} 
	}
	public ThreadPoolExecutor newFixThreadPool(int nThreads){  
		ThreadPoolExecutor ex =  new ThreadPoolExecutor(nThreads, nThreads, 1L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
		ex.allowCoreThreadTimeOut(true);
		return ex;
	}  
	private class fileSize{
		private DownloadTask work;
		private List<DownloadOneUrl> downloads = new ArrayList<DownloadOneUrl>();
	    /** 所有任务都一次性开始的线程池  */
	    private ThreadPoolExecutor mCacheThreadExecutor = null;

		private long totelLen = 0;
		private long doneLen = 0;
		public fileSize(DownloadTask work){
			this.work = work;
			//mCacheThreadExecutor = Executors.newFixedThreadPool(work.getUrlList().size());
			//new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
			mCacheThreadExecutor = newFixThreadPool(work.getUrlList().size());
		}
		
		public long getTotelLen(){
			return totelLen;
		}
		
		public long getDoneLen(){
			return doneLen;
		}
		
		public List<DownloadOneUrl> doGet(){			
			String savePath = work.getSavePath();// Constant.ROOT_JWAOO_GAME + "/" +// key;
			for (String url : work.getUrlList()) {		
				DownloadOneUrl download = new DownloadOneUrl(url, savePath);
				int index = work.getUrlList().indexOf(url);
				downloads.add(index, download);
				getFileSize(index);					
			}
			int count = downloads.size();
			do {
				count = downloads.size();;
				totelLen = 0;
				doneLen = 0;
				for (DownloadOneUrl download: downloads){
					if (download.getTotelLen() != 0){
						count--;
						totelLen += download.getTotelLen();
						doneLen += download.getDoneLen();
					}
					else{
						if (download.getError()){
							work.setDownloadState(DownloadTask.DownloadFailed);	
							work.involkManagerCb();
							mCacheThreadExecutor.shutdown();
							return null;
						}
					}
				}
				if (count > 0){
					try {
						Thread.sleep(200);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				if(work.Cancelled()){
					work.involkManagerCb();
					mCacheThreadExecutor.shutdown();

					return null;
				}
			}while(count > 0);
			
			return downloads;
		}
		private void getFileSize(final int index){
			mCacheThreadExecutor.execute(new Runnable() {
	            @Override
	            public void run() {
	            	MyLog.d(TAG, "Thread:" + Thread.currentThread().getId() + " activeCount:" + Thread.activeCount());
	    			int retries = work.getMaxRetry();
	    			DownloadOneUrl download = downloads.get(index);
	    			do {
	    				//取消下载
	    				if(work.Cancelled()){
	    					work.involkManagerCb();
	    					return;
	    				}
	    				
	    				MyLog.e(TAG," download try times count " +retries);
	    				download.startPre();
	    				if (download.getTotelLen() == 0 && retries -- <= 0) { 
	    					if(!download.getError()){
	    						MyLog.e(TAG, "get file size error, break");
	    						download.setError(true);
	    					}
	    					break;
	    				}
	    			}while (download.getTotelLen() == 0) ;
	    			MyLog.e(TAG, "get file len="+download.getTotelLen());
	            }
	        });
		}
	}
	

	
	private void doWork2(){
		
		
		MyLog.e(TAG, "getting task....");
		
		DownloadTask work = null;
		long startTime = -1;
		long intvalDoneLen = 0;
		int taskSize = 0;
		
		synchronized (this) {
			
			try {
				taskSize = tasks.size();
				
				work = taskSize>0?tasks.take():null;
			} catch (InterruptedException e1) {
				
				work = null;
				MyLog.e(TAG, "tasks.take InterruptedException:"+e1);
				e1.printStackTrace();
			}
			if (taskSize == 0){
				stoped = true;
				inWorking = null;
				return ;
			}
			inWorking = work;	
		}
		
		if(work==null){
			
			MyLog.e(TAG, "tasks.take() is null");
			
			return;
		}
		
		MyLog.e(TAG, "cur work is starting");
		
		work.setWaiting(false);
		work.setReTry(0);
		work.involkManagerCb();
		
		fileSize getSize = new fileSize(work);
		List<DownloadOneUrl> downloads = getSize.doGet();
		if (downloads == null){
			return;
		}
		boolean allFilesDone = true;
		long totelLen = getSize.getTotelLen();
		long doneLen = getSize.getDoneLen();
		
		//更新数据库总长度
		work.updateTotalLen(totelLen);
		DownloadOneUrl.ResetSpeed();
		for(DownloadOneUrl download:downloads){
			
			if(download.getProgress()==100){
				
				continue;
			}
			allFilesDone = false;
			int retries = work.getMaxRetry();
			
			do{
				startTime = -1;
				long tmpDoneLen = doneLen - download.getDoneLen();
				//开始下载前，前清除前面那次的错误
				download.setError(false);
				//开始下载
				download.start();
				MyLog.e(TAG, "is finised="+download.isFinished());
				//更新进度
				while(!download.isFinished()){
					
					//取消下载
					if(work.Cancelled()){
						
						MyLog.e(TAG, "User cancel download");
						download.cancelDownload();
					
						work.involkManagerCb();
						
						return;
						
						
					}
					
					long allLen = tmpDoneLen + download.getDoneLen();
					int calcProg = calcProgress(allLen, totelLen);		
					work.setDoneLen(allLen);
					if (work.getProgress() < calcProg)
						work.setProgress(calcProg);
					
					//MyLog.e(TAG, "url:" + download.getUrl());
					//MyLog.e(TAG, "doenlen=" + download.getDoneLen() + " progress=" + work.getProgress() + "  "
					//		+ calcProg);
//					if (startTime == -1){
//						startTime = System.currentTimeMillis();
//						intvalDoneLen = download.getDoneLen();
//					}else {
//						long endTime = System.currentTimeMillis();
//						long deltaTime = endTime - startTime;
//						if (deltaTime > 3000){
//							long endLen = download.getDoneLen();
//							long deltaLen = endLen - intvalDoneLen;
//							int speed = (int) (deltaLen/(deltaTime/1000));
//							speed = speed/1000;//kBps
//							DownloadTask.setSpeed(speed);
//							startTime = endTime;
//							intvalDoneLen = endLen;
//							MyLog.e(TAG, "download speed is "+speed+"KBps");
//							MyLog.e(TAG, "doenlen=" + download.getDoneLen() + " progress=" + work.getProgress() + "  "
//										+ calcProg);
//						}
//					}
					DownloadTask.setSpeed(download.getSpeed());
					MyLog.e(TAG, "download speed is "+download.getSpeed()+"KBps");
					if(calcProg<100)
						work.involkManagerCb();
					
					try {
						Thread.sleep(2 * 1000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					
				}
				
				//下载失败,进行下载重试
				if(download.getError()){
					retries--;
					MyLog.e(TAG, "download url"+download.getUrl()+" times:"+retries);
				}else{//下载完成
					
					doneLen += download.getTotelLen();
							
					break;
				}
	
				
			}while(retries>0);
			
			
			//当前资源下载失败
			if(retries==0){
				
				work.setDownloadState(DownloadTask.DownloadFailed);	
				work.involkManagerCb();
				return;
				
			}
				
			
		}
		
		int finalProgress = calcProgress(doneLen, totelLen);
		
		MyLog.d(TAG, "finalProgress="+finalProgress+ "allFilesDone="+allFilesDone);
		
		if (work.getProgress() < finalProgress)
			work.setProgress(finalProgress);
			
		if(allFilesDone||work.getProgress()>=100){
			
			MyLog.e(TAG,"allFiles is downloaded!");
			
			work.setProgress(100);
			work.involkManagerCb();
		}
	}
	

	public class UpdataThread extends Thread {
		public void run() {
			MyLog.e(TAG, "UpdataThread start");
			
			while(true){
				doWork2();
				synchronized (this){
					if(stoped){		
						break;
					}
				}
			}
			MyLog.e(TAG, "UpdataThread end");
		}
	}

	public void stopAll(){
		synchronized (this){
			tasks.clear();
			if (inWorking != null){
				inWorking.CancelTask();
			}
		}
	}
	
	public boolean addTask(DownloadTask task) {
		
		
		MyLog.e(TAG, "----addTask-----");
		
		task.setDownloadState(DownloadTask.DownloadDoing);
		task.setWaiting(true);
		task.setProgress(0);
		synchronized (this) {
			try {	
				tasks.put(task);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return false;
			}
				
			if (thread == null || stoped == true) {
				stoped = false;
				thread = new UpdataThread();
				thread.start();
			}
			return true;
		}
	}
	
	/**
	 * 取消任务
	 * @param task
	 * @return
	 */
	public boolean removeTask(DownloadTask task){
		
		synchronized (this) {
			
			task.CancelTask();
			
			if(inWorking!=task){
				
				MyLog.e(TAG, "cur DownloadTask is not working");
				if (inWorking == null){
					MyLog.e(TAG, "inWorking is null");
				}else{
					MyLog.e(TAG, "inWorking gameid="+inWorking.getGameId());
				}
				tasks.remove(task);	
					
				task.involkManagerCb();
			}else{
				
				MyLog.e(TAG, "cur DownloadTask is working");
				
			}
			
		}
			
		return true;
	}

	public interface DownloadCallBack {
		void progress(Object params, int progress, int DownloadState);
	}
	

}
